import datetime
import decimal
import json
from pathlib import Path
from uuid import UUID


class ScrapyJSONEncoder_ReW(json.JSONEncoder):
    DATE_FORMAT = "%Y-%m-%d"
    TIME_FORMAT = "%H:%M:%S"

    def default(self, o):
        if isinstance(o, set):
            return list(o)
        elif isinstance(o, datetime.datetime):
            return o.strftime(f"{self.DATE_FORMAT} {self.TIME_FORMAT}")
        elif isinstance(o, datetime.date):
            return o.strftime(self.DATE_FORMAT)
        elif isinstance(o, datetime.time):
            return o.strftime(self.TIME_FORMAT)
        elif isinstance(o, decimal.Decimal):
            return str(o)
        elif isinstance(o, UUID):
            return str(o)
        else:
            return super().default(o)


def jd(obj):
    return json.dumps(obj, ensure_ascii=False, cls=ScrapyJSONEncoder_ReW)


def jl(json_str):
    return json.loads(json_str)


def set_add(s, item):
    if not isinstance(s, set):
        raise TypeError
    l0 = len(s)
    s.add(item)
    l1 = len(s)
    if l1 - l0 == 1:
        return True
    else:
        return False


class SP:

    @classmethod
    def h_size(cls, file_path):
        size = Path(file_path).stat().st_size
        res = cls.size_h(size)
        return res

    @classmethod
    def size_h(cls, size: [int, float], unit=1024):
        if size > unit:
            hs = round(size / (unit), 2)
            if hs > unit:
                hs = round(size / (unit ** 2), 2)
                if hs > unit:
                    hs = round(size / (unit ** 3), 2)
                    if hs > unit:
                        hs = round(size / (unit ** 4), 2)
                        res = f'{hs}TB'
                    else:
                        res = f'{hs}GB'
                else:
                    res = f'{hs}MB'
            else:
                res = f'{hs}KB'
        else:
            if size:
                res = f'{size}B'
            else:
                res = 0
        return res

    @staticmethod
    def HH_mm_ss2s(HH_mm_ss: str) -> int:
        h, m, s = [int(i) for i in HH_mm_ss.split(':')]
        ss = h * 3600 + m * 60 + s
        return ss

    @staticmethod
    def s2HH_mm_ss(duration: int):
        h = duration // 3600
        m = (duration - 3600 * h) // 60
        s = duration - 3600 * h - 60 * m
        h = str(h)
        m = str(m) if len(str(m)) == 2 else '0' + str(m)
        s = str(s) if len(str(s)) == 2 else '0' + str(s)
        time_str = ':'.join([h, m, s])
        return time_str

    @classmethod
    def purge_string(self, instring):
        """
        去掉数据中的空格换行等字符
        :param instring:
        :return:
        """
        move = dict.fromkeys((ord(c) for c in u"\xa0\n\t|│:：<>？?\\/*’‘“”\"\x01\x02"))
        outstring = instring.translate(move)
        return outstring

    @staticmethod
    def save_text(file=None, text=None, mode='w'):
        file_path = Path(file).resolve()
        file_dir_path = file_path.parent
        Path(file_dir_path).mkdir(parents=True, exist_ok=True)
        with Path(file).open(mode, encoding='utf8') as f:
            f.write(text)

    @staticmethod
    def read_file(file):
        with Path(file).open(mode='r', encoding='utf-8') as f:
            content = f.read()
            return content

    @staticmethod
    def trans_json_text_to_json(text_file_path):
        with Path(text_file_path).open(mode='r', encoding='utf-8') as f:
            json_str = f.read()
        json_obj = json.loads(json_str)
        return json_obj

    @staticmethod
    def extract_from_dict(keys=[], data={}):
        '''返回data字典中包含keys字段的部分'''
        new_dict = {}
        for k in keys:
            new_dict[k] = data.get(k)
        return new_dict

    @staticmethod
    def dict_dumps_date_keys(data):
        new_data = {}
        for k, v in data.items():
            if 'datetime' in type(v):
                new_data[k] = str(v)
            else:
                new_data[k] = v

        return new_data

    @staticmethod
    def shorten_str(s, length=32):
        '''将字符串缩短至指定长度'''
        if len(s) <= length:
            res = s
        else:
            res = s[:length]
        return res.rstrip('.').strip()

    @classmethod
    def shorten_title(cls, s, length=32):
        return cls.shorten_str(s, length)

    @staticmethod
    def purify_file_name(file_name):
        forbidden_characters = list('''?'*:"<>\/|''') + ["\n"]
        substitute_characters = list('''？＇❋：＂〈〉↘↙↟''') + ['⏎']
        d = dict(zip(
            forbidden_characters,
            substitute_characters
        ))
        file_name = file_name.strip()
        for k, v in d.items():
            if k in file_name:
                file_name = file_name.replace(k, v)
        return file_name.strip()

    @classmethod
    def get_file_info(cls, file_abs_path: str) -> object:
        f = Path(file_abs_path)
        if not f.exists():
            raise FileNotFoundError

        stat = f.stat()

        class file_info:
            dir_path = str(f.parent)
            name = f.name
            ext = f.suffix.lstrip('.').lower()
            size = stat.st_size
            size_h = cls.size_h(stat.st_size)

        return file_info


if __name__ == "__main__":
    pass
